package utils

import (
	"bytes"
	"crypto/md5"
	"encoding/hex"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"github.com/golang-jwt/jwt/v4"
	"github.com/vueadmin/utils/conv"
	"github.com/vueadmin/utils/valid"
	"math/rand"
	"net/url"
	"reflect"
	"sort"
	"strings"
	"time"
)

// 获取客户端ip
func GetClientIP(c *gin.Context) string {
	ClientIP := c.ClientIP()
	RemoteIP := c.RemoteIP()
	ip := c.Request.Header.Get("X-Forwarded-For")
	if strings.Contains(ip, "127.0.0.1") || ip == "" {
		ip = c.Request.Header.Get("X-real-ip")
	}
	if ip == "" {
		ip = "127.0.0.1"
	}
	if RemoteIP != "127.0.0.1" {
		ip = RemoteIP
	}
	if ClientIP != "127.0.0.1" {
		ip = ClientIP
	}
	return ip
}

// 从协程上下文中解析出token
func GetClaims(name string, c *gin.Context) interface{} {
	data, exits := c.Get("claims")
	if exits {
		return data.(jwt.MapClaims)[name]
	}
	return nil
}

// 生成短信验证码
func GenerateSmsCode(length int) string {
	numberic := [10]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
	rand.Seed(time.Now().Unix())
	var sb strings.Builder
	for i := 0; i < length; i++ {
		fmt.Fprintf(&sb, "%d", numberic[rand.Intn(len(numberic))])
	}
	return sb.String()
}

// MD5加密
func Md5(str string) string {
	h := md5.New()
	h.Write([]byte(str))
	return hex.EncodeToString(h.Sum(nil))
}

// map转http_query_string
func HttpBuildQuery(data map[string]interface{}) string {
	queryString := url.Values{}
	keys := conv.GetMapKeys(data)

	sort.Strings(keys)

	for _, val := range keys {
		queryString.Set(val, conv.String(data[val]))
	}
	return queryString.Encode()
}

// 生成随机字符串
func Rand(codeLen int, pattern string) string {
	rawStr := map[string]string{
		"number": "1234567890",
		"letter": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
		"string": "abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789",
		"all":    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
	}
	buf := make([]byte, 0, codeLen)
	b := bytes.NewBuffer(buf)
	rand.Seed(time.Now().UnixNano())
	for rawStrLen := len(rawStr[pattern]); codeLen > 0; codeLen-- {
		randNum := rand.Intn(rawStrLen)
		b.WriteByte(rawStr[pattern][randNum])
	}
	return b.String()
}

// map结构生成树
func GenerateListTree(data []map[string]interface{}, pid int, config []string) []map[string]interface{} {
	var tmp []map[string]interface{}
	for _, val := range data {
		if conv.Int(val[config[1]]) == pid {
			val["children"] = GenerateListTree(data, conv.Int(val[config[0]]), config)
			tmp = append(tmp, val)
		}
	}
	return tmp
}

// 生成订单流水号 日期20191025时间戳1571987125435+3位随机数
func DoOrderSn() string {
	r := rand.Intn(1000)
	code := fmt.Sprintf("%s%d%03d", time.Now().Format("20060102"), time.Now().UnixNano()/1e6, r)
	return code
}

// 绑定并且验证
func BindAndValid(c *gin.Context, form interface{}) error {
	if err := c.ShouldBind(form); err != nil {
		return errors.New("参数格式错误:" + err.Error())
	}
	if reflect.TypeOf(form).Kind() == reflect.Ptr && reflect.ValueOf(form).Elem().Kind() == reflect.Struct {
		if err := valid.Validate.Struct(form); err != nil {
			for _, error := range err.(validator.ValidationErrors) {
				return errors.New(error.Translate(valid.Trans))
			}
		}
	}
	return nil
}
